#include "../my_time.h"
#include <omp.h>
#include <string>

#ifdef _MSVC_LANG
#include <windows.h>
#define sleep Sleep
#else
#include <unistd.h>
#endif

struct Node {
  Node(Node *l, Node *r, const std::string &n) : left(l), right(r), name(n) {}
  Node *left;
  Node *right;
  std::string name;
  int id = 0;
};

std::string genSpace(int lev, char s) {
  std::string ispa;
  for (size_t i = 0; i < lev; i++)
    ispa.push_back(s);
  return ispa;
}

void process(Node *p, int lev) {
  sleep(1);
  auto id = omp_get_thread_num();

  printf("%sid %d; node's name: %s\n", genSpace(lev, ' ').c_str(), id,
         p->name.c_str());
  // printf("node's name: %s", p->name.c_str());
};

// ------- traverse node
void traverse(Node *p, int level) {

  if (p->left)
#pragma omp task
    // p is firstprivate by default
    traverse(p->left, level + 1);

  if (p->right)
#pragma omp task
    // p is firstprivate by default
    traverse(p->right, level + 1);

#pragma omp taskwait
  process(p, level + 1);
}

// ---- level 0; bottom
auto l0 = Node(nullptr, nullptr, "leaf 0");
auto l1 = Node(nullptr, nullptr, "leaf 1");
auto l2 = Node(nullptr, nullptr, "leaf 2");
auto l3 = Node(nullptr, nullptr, "leaf 3");
// --- level 1;
auto n01 = Node(&l0, &l1, "node 0, 1");
auto n02 = Node(&l2, &l3, "node 0, 2");

//--- level 2
auto n10 = Node(&n01, &n02, "node 1, 0");

int main() {
  //   omp_set_num_threads(4);
  MyTimeI;
  MyTimeA;

#pragma omp parallel num_threads(4)
  traverse(&n10, 0);

  MyTimeB;
  return 0;
}
